/*Copyright (C) 2014  JD Software, Inc.

  This program is free software: you can redistribute it and/or modify
  it under the terms of the GNU Affero General Public License as
  published by the Free Software Foundation, either version 3 of the
  License, or (at your option) any later version.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU Affero General Public License for more details.

  You should have received a copy of the GNU Affero General Public License
  along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/
package com.jd.survey.service.settings;

import java.io.StringWriter;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.Velocity;
import org.joda.time.DateTime;
import org.joda.time.Months;
import org.joda.time.Weeks;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.MessageSource;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.dao.DataAccessException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.jd.survey.dao.interfaces.settings.DataSetDAO;
import com.jd.survey.dao.interfaces.settings.DataSetItemDAO;
import com.jd.survey.dao.interfaces.settings.DayDAO;
import com.jd.survey.dao.interfaces.settings.DepartmentDAO;
import com.jd.survey.dao.interfaces.settings.InvitationDAO;
import com.jd.survey.dao.interfaces.settings.QuestionColumnLabelDAO;
import com.jd.survey.dao.interfaces.settings.QuestionDAO;
import com.jd.survey.dao.interfaces.settings.QuestionOptionDAO;
import com.jd.survey.dao.interfaces.settings.QuestionRowLabelDAO;
import com.jd.survey.dao.interfaces.settings.RegularExpressionDAO;
import com.jd.survey.dao.interfaces.settings.SectorDAO;
import com.jd.survey.dao.interfaces.settings.SurveyDefinitionDAO;
import com.jd.survey.dao.interfaces.settings.SurveyDefinitionPageDAO;
import com.jd.survey.dao.interfaces.settings.SurveyTemplateDAO;
import com.jd.survey.dao.interfaces.settings.VelocityTemplateDAO;
import com.jd.survey.dao.interfaces.survey.ReportDAO;
import com.jd.survey.dao.interfaces.survey.SurveyDAO;
import com.jd.survey.domain.security.User;
import com.jd.survey.domain.settings.DataSet;
import com.jd.survey.domain.settings.DataSetItem;
import com.jd.survey.domain.settings.Day;
import com.jd.survey.domain.settings.Department;
import com.jd.survey.domain.settings.Invitation;
import com.jd.survey.domain.settings.Question;
import com.jd.survey.domain.settings.QuestionColumnLabel;
import com.jd.survey.domain.settings.QuestionOption;
import com.jd.survey.domain.settings.QuestionRowLabel;
import com.jd.survey.domain.settings.QuestionType;
import com.jd.survey.domain.settings.RegularExpression;
import com.jd.survey.domain.settings.Sector;
import com.jd.survey.domain.settings.SurveyDefinition;
import com.jd.survey.domain.settings.SurveyDefinitionPage;
import com.jd.survey.domain.settings.SurveyDefinitionStatus;
import com.jd.survey.domain.settings.SurveyTemplate;
import com.jd.survey.domain.settings.VelocityTemplate;
import com.jd.survey.service.email.MailService;

import au.com.bytecode.opencsv.CSVReader;

@Transactional(readOnly = true)
@Service("SurveySettingsService")
public class SurveySettingsService {

    private static final Log log = LogFactory.getLog(SurveySettingsService.class);

    @Autowired
    private MessageSource messageSource;
    @Autowired
    private DepartmentDAO departmentDAO;
    @Autowired
    private SurveyDefinitionDAO surveyDefinitionDAO;
    @Autowired
    private SurveyDefinitionPageDAO surveyDefinitionPageDAO;
    @Autowired
    private QuestionOptionDAO questionOptionDAO;
    @Autowired
    private QuestionRowLabelDAO rowLabelDAO;
    @Autowired
    private QuestionColumnLabelDAO columnLabelDAO;

    @Autowired
    private QuestionRowLabelDAO questionRowLabelDAO;
    @Autowired
    private QuestionColumnLabelDAO questionColumnLabelDAO;
    @Autowired
    private QuestionDAO questionDAO;
    @Autowired
    private DataSetDAO dataSetDAO;
    @Autowired
    private DataSetItemDAO dataSetItemDAO;
    @Autowired
    private VelocityTemplateDAO velocityTemplateDAO;
    @Autowired
    private RegularExpressionDAO regularExpressionDAO;

    @Autowired
    private SurveyDAO surveyDAO;
    @Autowired
    private InvitationDAO invitationDAO;
    @Autowired
    private MailService mailService;
    @Autowired
    private SectorDAO sectorDAO;
    @Autowired
    private SurveyTemplateDAO surveyTemplateDAO;
    @Autowired
    private DayDAO dayDAO;
    @Autowired
    private ReportDAO reportDAO;

    private static final String INVITATION_EMAIL_TITLE = "invitation_email_title";
    private static final String INVITEE_FULLNAME_PARAMETER_NAME = "invitee_fullname_parameter_name";
    private static final String SURVEY_NAME = "survey_name";
    private static final String INVITE_FILL_SURVEY_LINK_PARAMETER_NAME = "invite_fill_survey_link_parameter_name";
    private static final String INVITE_FILL_SURVEY_LINK_LABEL = "invite_fill_survey_link_label";
    private static final String INTERNAL_SITE_BASE_URL = "internal_site_base_url";
    private static final String EXTERNAL_SITE_BASE_URL = "external_site_base_url";

    public Set<Department> department_findAll() throws DataAccessException {
        return departmentDAO.findAll();
    }

    public Set<Department> department_findAll(int startResult, int maxRows) throws DataAccessException {
        return departmentDAO.findAll(startResult, maxRows);
    }

    public Set<Department> department_findAll(User user) throws DataAccessException {

        if (user.isAdmin()) {
            return departmentDAO.findAll();
        } else {
            return departmentDAO.getUserDepartments(user.getLogin(), -1, -1);

        }
    }

    public Long department_getCount() {
        return departmentDAO.getCount();
    }

    public Department department_findById(Long id) {
        return departmentDAO.findById(id);
    }

    public Department department_findByName(String name) {
        return departmentDAO.findByName(name);
    }

    @Transactional(readOnly = false)
    public Department department_merge(Department department) {
        return departmentDAO.merge(department);
    }

    @Transactional(readOnly = false)
    public void department_remove(Department department) {
        departmentDAO.remove(department);
    }

    public boolean question_ValidateMinMaxDoubleValues(Question question) {
        if (question.getType() == QuestionType.CURRENCY_INPUT
                || question.getType() == QuestionType.DECIMAL_INPUT) {
            if (question.getDecimalMinimum() != null && question.getDecimalMaximum() != null && question
                    .getDecimalMinimum().doubleValue() >= question.getDecimalMaximum().doubleValue()) {
                return false;
            }
        }
        return true;
    }

    public boolean question_ValidateMinMaxValues(Question question) {
        if (question.getType() == QuestionType.INTEGER_INPUT
                || question.getType() == QuestionType.SHORT_TEXT_INPUT
                || question.getType() == QuestionType.LONG_TEXT_INPUT
                || question.getType() == QuestionType.HUGE_TEXT_INPUT) {
            if (question.getIntegerMinimum() != null && question.getIntegerMaximum() != null
                    && question.getIntegerMinimum() >= question.getIntegerMaximum()) {
                return false;
            }
        }
        return true;
    }

    public boolean question_ValidateDateRange(Question question) {
        if (question.getDateMinimum() != null && question.getDateMaximum() != null
                && question.getDateMinimum().after(question.getDateMaximum())) {
            return false;
        }
        return true;
    }

    public Set<SurveyDefinition> surveyDefinition_findAllInternal(User user) throws DataAccessException {
        if (user.isAdmin()) {
            return surveyDefinitionDAO.findAllInternal(-1, -1);
        } else {
            return surveyDefinitionDAO.findAllInternal(user.getLogin(), -1, -1);
        }
    }

    public Set<SurveyDefinition> surveyDefinition_findAllInternal(User user, int startResult, int maxRows)
            throws DataAccessException {
        if (user.isAdmin()) {
            return surveyDefinitionDAO.findAllInternal(startResult, maxRows);
        } else {
            return surveyDefinitionDAO.findAllInternal(user.getLogin(), startResult, maxRows);
        }
    }

    public Set<SurveyDefinition> surveyDefinition_findAllCompletedInternal(User user)
            throws DataAccessException {
        if (user.isAdmin()) {
            return surveyDefinitionDAO.findAllCompletedInternal(-1, -1);
        } else {
            return surveyDefinitionDAO.findAllCompletedInternal(user.getLogin(), -1, -1);
        }
    }

    public Set<SurveyDefinition> surveyDefinition_findAllCompletedInternal(User user, int startResult,
            int maxRows) throws DataAccessException {
        if (user.isAdmin()) {
            return surveyDefinitionDAO.findAllCompletedInternal(startResult, maxRows);
        } else {
            return surveyDefinitionDAO.findAllCompletedInternal(user.getLogin(), startResult, maxRows);
        }
    }

    public Set<SurveyDefinition> surveyDefinition_findAllPublishedInternal(User user)
            throws DataAccessException {
        if (user.isAdmin()) {
            return surveyDefinitionDAO.findAllPublishedInternal(-1, -1);
        } else {
            return surveyDefinitionDAO.findAllPublishedInternal(user.getLogin(), -1, -1);
        }
    }

    public Set<SurveyDefinition> surveyDefinition_findAllPublishedInternal(User user, int startResult,
            int maxRows) throws DataAccessException {
        if (user.isAdmin()) {
            return surveyDefinitionDAO.findAllPublishedInternal(startResult, maxRows);
        } else {
            return surveyDefinitionDAO.findAllPublishedInternal(user.getLogin(), startResult, maxRows);
        }
    }

    public Set<SurveyDefinition> surveyDefinition_findAllPublishedExternal(User user)
            throws DataAccessException {
        if (user.isAdmin()) {
            Set<SurveyDefinition> surveyDefinitions = surveyDefinitionDAO.findAllPublishedInternal(-1, -1);
            return surveyDefinitions;
        }
        if (user.isSurveyAdmin()) {
            return surveyDefinitionDAO.findAllPublishedInternal(user.getLogin(), -1, -1);
        } else {
            return surveyDefinitionDAO.findAllPublishedExternal(user.getLogin(), -1, -1);
        }
    }

    public Set<SurveyDefinition> surveyDefinition_findAllPublishedExternal(User user, int startResult,
            int maxRows) throws DataAccessException {
        if (user.isAdmin()) {
            return surveyDefinitionDAO.findAllPublishedInternal(startResult, maxRows);
        }
        if (user.isSurveyAdmin()) {
            return surveyDefinitionDAO.findAllPublishedInternal(user.getLogin(), startResult, maxRows);
        } else {
            return surveyDefinitionDAO.findAllPublishedExternal(user.getLogin(), startResult, maxRows);
        }
    }

    public Set<SurveyDefinition> surveyDefinition_findAllPublishedPublic() throws DataAccessException {
        return surveyDefinitionDAO.findAllPublishedPublic();
    }

    public Set<SurveyDefinition> surveyDefinition_findAllPublishedPublic(int startResult, int maxRows)
            throws DataAccessException {
        return surveyDefinitionDAO.findAllPublishedPublic(startResult, maxRows);
    }

    public Long surveyDefinition_getCount() {
        return surveyDefinitionDAO.getCount();
    }

    public SurveyDefinition surveyDefinition_findById(Long id) {
        return surveyDefinitionDAO.findById(id);
    }

    public SurveyDefinition surveyDefinition_findByIdEager(Long id) {
        return surveyDefinitionDAO.findByIdEager(id);
    }

    // @Transactional(readOnly = false)
    // public SurveyDefinition surveyDefinition_merge(SurveyDefinition surveyDefinition) {
    // surveyDefinition.setDepartment(departmentDAO.findById(surveyDefinition.getDepartment().getId()));
    // return surveyDefinitionDAO.merge(surveyDefinition);}

    @Transactional(readOnly = false)
    public SurveyDefinition surveyDefinition_merge(SurveyDefinition surveyDefinition) {
        if (surveyDefinition.getId() == null) {
            surveyDefinition.setDepartment(departmentDAO.findById(surveyDefinition.getDepartment().getId()));
            return surveyDefinitionDAO.merge(surveyDefinition);
        }

        else {
            SurveyDefinition dbSurveyDefinition = surveyDefinitionDAO.findById(surveyDefinition.getId());
            dbSurveyDefinition.setName(surveyDefinition.getName());
            dbSurveyDefinition.setSurveyTheme(surveyDefinition.getSurveyTheme());
            dbSurveyDefinition.setDescription(surveyDefinition.getDescription());
            dbSurveyDefinition.setEmailInvitationTemplate(surveyDefinition.getEmailInvitationTemplate());
            dbSurveyDefinition.setCompletedSurveyTemplate(surveyDefinition.getCompletedSurveyTemplate());
            dbSurveyDefinition.setAutoRemindersDayOfMonth(surveyDefinition.getAutoRemindersDayOfMonth());
            dbSurveyDefinition.setAutoRemindersDays(surveyDefinition.getAutoRemindersDays());
            dbSurveyDefinition.setAutoRemindersFrequency(surveyDefinition.getAutoRemindersFrequency());
            dbSurveyDefinition
                    .setAutoRemindersMonthlyOccurrence(surveyDefinition.getAutoRemindersMonthlyOccurrence());
            dbSurveyDefinition
                    .setAutoRemindersWeeklyOccurrence(surveyDefinition.getAutoRemindersWeeklyOccurrence());
            dbSurveyDefinition.setCompletedSurveyTemplate(surveyDefinition.getCompletedSurveyTemplate());
            dbSurveyDefinition.setSendAutoReminders(surveyDefinition.getSendAutoReminders());
            dbSurveyDefinition.setAllowMultipleSubmissions(surveyDefinition.getAllowMultipleSubmissions());
            dbSurveyDefinition.setIsPublic(surveyDefinition.getIsPublic());
            surveyDefinition.setDepartment(departmentDAO.findById(surveyDefinition.getDepartment().getId()));
            return surveyDefinitionDAO.merge(dbSurveyDefinition);

        }
    }

    @Transactional(readOnly = false)
    public SurveyDefinition surveyDefinition_update(SurveyDefinition surveyDefinition) {

        surveyDefinition.setStatus(SurveyDefinitionStatus.P);
        return surveyDefinitionDAO.merge(surveyDefinition);
    }

    @Transactional(readOnly = false)
    public SurveyDefinition surveyDefinition_updateLogo(Long id, byte[] logo) {
        SurveyDefinition surveyDefinition = surveyDefinitionDAO.findById(id);
        surveyDefinition.setLogo(logo);
        return surveyDefinitionDAO.merge(surveyDefinition);
    }

    @Transactional(readOnly = false)
    public SurveyDefinition surveyDefinition_create(SurveyDefinition surveyDefinition, Long departmentId) {
        surveyDefinition.setDepartment(departmentDAO.findById(departmentId));
        SortedSet<SurveyDefinitionPage> pages = surveyDefinition.getPages();
        surveyDefinition = surveyDefinitionDAO.merge(surveyDefinition);

        for (SurveyDefinitionPage page : pages) {
            page.setSurveyDefinition(surveyDefinition);
            SortedSet<Question> questions = page.getQuestions();
            page = surveyDefinitionPageDAO.merge(page);
            for (Question question : questions) {
                question.setPage(page);
                SortedSet<QuestionOption> options = question.getOptions();
                SortedSet<QuestionRowLabel> rowLabels = question.getRowLabels();
                SortedSet<QuestionColumnLabel> columnLabels = question.getColumnLabels();
                question = questionDAO.merge(question);
                for (QuestionOption option : options) {
                    option.setQuestion(question);
                    option = questionOptionDAO.merge(option);
                }
                question.setOptions(options);
                for (QuestionRowLabel rowLabel : rowLabels) {
                    rowLabel.setQuestion(question);
                    rowLabel = rowLabelDAO.merge(rowLabel);
                }
                question.setRowLabels(rowLabels);
                for (QuestionColumnLabel columnLabel : columnLabels) {
                    columnLabel.setQuestion(question);
                    columnLabel = columnLabelDAO.merge(columnLabel);
                }
                question.setColumnLabels(columnLabels);
            }
            page.setQuestions(questions);
        }
        surveyDefinition.setPages(pages);
        return surveyDefinitionDAO.merge(surveyDefinition);

    }

    @Transactional(readOnly = false)
    public void surveyDefinition_remove(SurveyDefinition surveyDefinition) {

        for (SurveyDefinitionPage page : surveyDefinition.getPages()) {
            for (Question question : page.getQuestions()) {
                log.info("deleting  questionOptions");
                questionOptionDAO.deleteByQuestionId(question.getId());
                rowLabelDAO.deleteByQuestionId(question.getId());
                columnLabelDAO.deleteByQuestionId(question.getId());
            }
            log.info("deleting  questions");
            questionDAO.deleteBySurveyDefinitionPageId(page.getId());
        }
        log.info("deleting  SurveyDefinitionPages");
        surveyDefinitionPageDAO.deleteBySurveyDefinitionId(surveyDefinition.getId());

        surveyDefinition.setPages(null);
        surveyDefinitionDAO.remove(surveyDefinition);

    }

    public Set<SurveyDefinition> surveyDefinition_findByName(String name) throws DataAccessException {
        return surveyDefinitionDAO.findByName(name);
    }

    public Boolean surveyDefinition_ValidateNameIsUnique(SurveyDefinition surveyDefinition)
            throws DataAccessException {
        Boolean isValid = true;
        // get all survey definitions with the same name
        Set<SurveyDefinition> surveyDefinitions = surveyDefinitionDAO.findByName(surveyDefinition.getName());

        // Insert case null id
        if (surveyDefinition.getId() == null) {
            // check that there are not survey types with the same name under the current
            // department
            for (SurveyDefinition appType : surveyDefinitions) {
                if (appType.getDepartment().getId().equals(surveyDefinition.getDepartment().getId())) {
                    isValid = false;
                    break;
                }
            }
        }
        // Update case id not null
        else {
            // check that there are no other survey types with the same name under the current
            // department
            for (SurveyDefinition appType : surveyDefinitions) {
                if (appType.getDepartment().getId().equals(surveyDefinition.getDepartment().getId())
                        && !appType.getId().equals(surveyDefinition.getId())) {
                    isValid = false;
                    break;
                }
            }
        }
        return isValid;
    }

    /**
     * Validates the Survey Questions. 
     * It will return false if there is an empty page or a survey question without options 
     *    
     */
    public Boolean surveyDefinition_ValidateSurveydefinitionForPublishing(Long id) {
        SurveyDefinition surveyDefinition = surveyDefinitionDAO.findById(id);
        if (surveyDefinition.getPages().isEmpty()) {
            return false; // no pages
        }
        for (SurveyDefinitionPage page : surveyDefinition.getPages()) {
            if (page.getQuestions().isEmpty()) {
                return false; // empty page
            }
            for (Question question : page.getQuestions()) {
                // Questions with Options
                if (question.getType().getRequiresOptions()) {
                    if (question.getOptions().isEmpty()) {
                        return false; // Multiple choice question with no options
                    }
                }
                // Matrix Questions
                if (question.getType().getIsMatrix()) {
                    if (question.getColumnLabels().isEmpty()) {
                        return false; // Matrix question with no column labels
                    }
                    if (question.getRowLabels().isEmpty()) {
                        return false; // Matrix question with no row labels
                    }
                }
            }
        }
        return true;
    }

    @Transactional(readOnly = false)
    public SurveyDefinition surveyDefinition_publish(Long id) {
        SurveyDefinition surveyDefinition = surveyDefinitionDAO.findById(id);
        if (surveyDefinition.getStatus().equals(SurveyDefinitionStatus.I)) {
            surveyDAO.publish(surveyDefinition);
        }
        surveyDefinition.setStatus(SurveyDefinitionStatus.P);
        return surveyDefinitionDAO.merge(surveyDefinition);
    }

    @Transactional(readOnly = false)
    public SurveyDefinition surveyDefinition_deactivate(Long id) {
        SurveyDefinition surveyDefinition = surveyDefinitionDAO.findById(id);
        surveyDefinition.setStatus(SurveyDefinitionStatus.D);
        return surveyDefinitionDAO.merge(surveyDefinition);
    }

    public Set<SurveyDefinition> surveyDefinition_findByUserLogin(User user) throws DataAccessException {
        return surveyDefinitionDAO.getSurveyDefinitionUsers(user.getLogin(), -1, -1);
    }

    public Set<SurveyDefinition> surveydefinition_findAll(User user) throws DataAccessException {

        return surveyDefinitionDAO.getSurveyDefinitionUsers(user.getLogin(), -1, -1);

    }

    @Transactional()
    @SuppressWarnings("unchecked")
    public void sendEmailReminder(SurveyDefinition surveyDefinition) {
        try {
            StringWriter sw = new StringWriter();
            Map<String, String> model = new HashMap<String, String>();

            for (User user : surveyDefinition.getUsers()) {
                String emailSubject = messageSource.getMessage(INVITATION_EMAIL_TITLE, null,
                        LocaleContextHolder.getLocale());
                String surveyLink = messageSource.getMessage(EXTERNAL_SITE_BASE_URL, null,
                        LocaleContextHolder.getLocale());
                String trackingImageLink = messageSource.getMessage(INTERNAL_SITE_BASE_URL, null,
                        LocaleContextHolder.getLocale());

                if (trackingImageLink.endsWith("/")) {
                    trackingImageLink = trackingImageLink + "public/w/";
                } else {
                    trackingImageLink = trackingImageLink + "/public/w/";
                }
                if (surveyLink.endsWith("/")) {
                    surveyLink = surveyLink + "private/";
                } else {
                    surveyLink = surveyLink + "/private/";
                }

                String emailContent = "";
                Invitation invitation = new Invitation(user.getFirstName().trim(), user.getMiddleName().trim(),
                        user.getLastName().trim(), user.getEmail().trim(), surveyDefinition);

                // survey name
                model.put(messageSource.getMessage(SURVEY_NAME, null, LocaleContextHolder.getLocale())
                        .replace("${", "").replace("}", ""), surveyDefinition.getName());
                // full name
                model.put(
                        messageSource.getMessage(INVITEE_FULLNAME_PARAMETER_NAME, null,
                                LocaleContextHolder.getLocale()).replace("${", "").replace("}", ""),
                        user.getFullName());
                // survey link
                model.put(
                        messageSource.getMessage(INVITE_FILL_SURVEY_LINK_PARAMETER_NAME, null,
                                LocaleContextHolder.getLocale()).replace("${", "").replace("}", ""),
                        "<a href='" + surveyLink + surveyDefinition.getId() + "?list'>"
                                + messageSource.getMessage(INVITE_FILL_SURVEY_LINK_LABEL, null,
                                        LocaleContextHolder.getLocale())
                                + "</a>");

                VelocityContext velocityContext = new VelocityContext(model);
                Velocity.evaluate(velocityContext, sw, "velocity-log",
                        surveyDefinition.getEmailInvitationTemplate());
                emailContent = sw.toString().trim();

                if (emailContent.length() > 14 && emailContent.substring(emailContent.length() - 14)
                        .toUpperCase().equalsIgnoreCase("</BODY></HTML>")) {
                    emailContent = emailContent.substring(0, emailContent.length() - 14) + "<img src='"
                            + trackingImageLink + invitation.getUuid() + "'/></BODY></HTML>";
                } else {
                    // template is incorrect or not html do not include tracking white gif
                    // emailContent = emailContent + "<img src='" + trackingImageLink +
                    // invitation.getUuid() + "'/></BODY></HTML>";
                }
                surveyDefinition.setAutoReminderLastSentDate(new Date());
                mailService.sendEmail(user.getEmail(), emailSubject, emailContent);

            }
        } catch (RuntimeException e) {
            log.error(e.getMessage(), e);
            System.out.println(e);
            throw (new RuntimeException(e));
        }
    }

    @Transactional(readOnly = false)
    @SuppressWarnings("unchecked")
    public void sendEmailReminders() {
        try {
            int currentDayOfWeek = new DateTime().getDayOfWeek();
            int currentDayOfMonth = new DateTime().getDayOfMonth();
            DateTime todayDateTime = new DateTime();

            for (SurveyDefinition surveyDefinition : surveyDefinitionDAO.findAllInternal()) {
                if (surveyDefinition.getSendAutoReminders() && surveyDefinition.getUsers().size() > 0
                        && surveyDefinition.getStatusAsString().equals("P")) {
                    Date lastSentDate = surveyDefinition.getAutoReminderLastSentDate();
                    switch (surveyDefinition.getAutoRemindersFrequency()) {
                        case WEEKLY:
                            int weeks;
                            if (lastSentDate != null) {
                                weeks = Weeks.weeksBetween(new DateTime(lastSentDate), todayDateTime)
                                        .getWeeks();
                            }

                            else {
                                weeks = 1000;
                            }
                            if (weeks >= surveyDefinition.getAutoRemindersWeeklyOccurrence()) {
                                for (Day day : surveyDefinition.getAutoRemindersDays()) {
                                    if (day.getId().equals(new Long(currentDayOfWeek))) {
                                        sendEmailReminder(surveyDefinition);

                                    }
                                }
                            }
                            break;
                        case MONTHLY:
                            int months;
                            if (lastSentDate != null) {
                                months = Months.monthsBetween(new DateTime(lastSentDate), todayDateTime)
                                        .getMonths();
                            } else {
                                months = 1000;
                            }
                            if (months >= surveyDefinition.getAutoRemindersMonthlyOccurrence()
                                    && surveyDefinition.getAutoRemindersDayOfMonth()
                                            .equals(currentDayOfMonth)) {
                                sendEmailReminder(surveyDefinition);
                            }
                            break;
                    }
                }
            }
        } catch (RuntimeException e) {
            log.error(e.getMessage(), e);
        }
    }

    public Set<SurveyDefinitionPage> surveyDefinitionPage_findAll() throws DataAccessException {
        return surveyDefinitionPageDAO.findAll();
    }

    public Set<SurveyDefinitionPage> surveyDefinitionPage_findAll(int startResult, int maxRows)
            throws DataAccessException {
        return surveyDefinitionPageDAO.findAll(startResult, maxRows);
    }

    public Long surveyDefinitionPage_getCount() {
        return surveyDefinitionPageDAO.getCount();
    }

    public SurveyDefinitionPage surveyDefinitionPage_findById(Long id) {
        return surveyDefinitionPageDAO.findById(id);
    }

    @Transactional(readOnly = false)
    public SurveyDefinitionPage surveyDefinitionPage_merge(SurveyDefinitionPage surveyDefinitionPage) {
        SortedSet<SurveyDefinitionPage> updatedSurveyDefinitionPages = new TreeSet<SurveyDefinitionPage>();
        Long AppTypeId = surveyDefinitionPage.getSurveyDefinition().getId();
        SurveyDefinition surveyDefinition = surveyDefinitionDAO.findById(AppTypeId);
        surveyDefinitionPage.setSurveyDefinition(surveyDefinition);
        Short order = surveyDefinition.updateSet(surveyDefinition.getPages(), surveyDefinitionPage).getOrder();
        for (SurveyDefinitionPage atp : surveyDefinition.getPages()) {
            updatedSurveyDefinitionPages.add(surveyDefinitionPageDAO.merge(atp));
        }
        surveyDefinition.setPages(updatedSurveyDefinitionPages);
        surveyDefinition = surveyDefinitionDAO.merge(surveyDefinition);
        return surveyDefinition.getElement(surveyDefinition.getPages(), order);
    }

    @Transactional(readOnly = false)
    public void surveyDefinitionPage_updateSkipAndBranckLogic(SurveyDefinitionPage surveyDefinitionPage) {
        SurveyDefinitionPage dbsurveyDefinitionPage = surveyDefinitionPageDAO
                .findById(surveyDefinitionPage.getId());
        dbsurveyDefinitionPage.setPageLogic(surveyDefinitionPage.getPageLogic());
        dbsurveyDefinitionPage.updateJson();
        surveyDefinitionPageDAO.merge(dbsurveyDefinitionPage);

    }

    @Transactional(readOnly = false)
    public void surveyDefinitionPage_remove(SurveyDefinitionPage surveyDefinitionPage) {
        SurveyDefinition surveyDefinition = surveyDefinitionDAO
                .findById(surveyDefinitionPage.getSurveyDefinition().getId());
        for (Question question : surveyDefinitionPage.getQuestions()) {
            log.info("deleting  questionOptions");
            questionOptionDAO.deleteByQuestionId(question.getId());
            rowLabelDAO.deleteByQuestionId(question.getId());
            columnLabelDAO.deleteByQuestionId(question.getId());
        }
        log.info("deleting  questions");
        questionDAO.deleteBySurveyDefinitionPageId(surveyDefinitionPage.getId());
        surveyDefinitionPage.setQuestions(null);
        surveyDefinitionPageDAO.remove(surveyDefinitionPage);
        surveyDefinition.removeGaps(surveyDefinition.getPages());
    }

    public Boolean surveyDefinitionPage_ValidateTitleIsUnique(SurveyDefinitionPage surveyDefinitionPage)
            throws DataAccessException {
        Boolean isValid = true;
        // get all appplication types with the same name
        Set<SurveyDefinitionPage> surveyDefinitionPages = surveyDefinitionPageDAO
                .findByTitle(surveyDefinitionPage.getTitle());

        // Insert case null id
        if (surveyDefinitionPage.getId() == null) {
            // check that there are not survey types with the same name under the current
            // Department
            for (SurveyDefinitionPage atp : surveyDefinitionPages) {
                if (atp.getSurveyDefinition().getId()
                        .equals(surveyDefinitionPage.getSurveyDefinition().getId())) {
                    isValid = false;
                    break;
                }
            }
        }
        // Update case id not null
        else {
            // check that there are no other survey types with the same name under the current
            // license
            for (SurveyDefinitionPage atp : surveyDefinitionPages) {
                if (atp.getSurveyDefinition().getId().equals(surveyDefinitionPage.getSurveyDefinition().getId())
                        &&

                        !atp.getId().equals(surveyDefinitionPage.getId())) {

                    isValid = false;
                    break;
                }
            }
        }
        return isValid;
    }

    public Set<VelocityTemplate> velocityTemplate_findAll() throws DataAccessException {
        return velocityTemplateDAO.findAll();
    }

    public Set<VelocityTemplate> velocityTemplate_findAll(int startResult, int maxRows)
            throws DataAccessException {
        return velocityTemplateDAO.findAll(startResult, maxRows);
    }

    public Long velocityTemplate_getCount() {
        return velocityTemplateDAO.getCount();
    }

    public VelocityTemplate velocityTemplate_findById(Long id) {
        return velocityTemplateDAO.findById(id);
    }

    public VelocityTemplate velocityTemplate_findByName(String templateName) {
        return velocityTemplateDAO.findByName(templateName);
    }

    @Transactional(readOnly = false)
    public VelocityTemplate velocityTemplate_merge(VelocityTemplate velocityTemplate) {
        velocityTemplate.setTimestamp(new Date());
        return velocityTemplateDAO.merge(velocityTemplate);
    }

    @Transactional(readOnly = false)
    public void velocityTemplate_remove(VelocityTemplate velocityTemplate) {
        velocityTemplateDAO.remove(velocityTemplate);
    }

    public Set<QuestionOption> questionOption_findAll() throws DataAccessException {
        return questionOptionDAO.findAll();
    }

    public Set<QuestionOption> questionOption_findAll(int startResult, int maxRows) throws DataAccessException {
        return questionOptionDAO.findAll(startResult, maxRows);
    }

    public Long questionOption_getCount() {
        return questionOptionDAO.getCount();
    }

    public QuestionOption questionOption_findById(Long id) {
        return questionOptionDAO.findById(id);
    }

    public Set<QuestionOption> questionOption_findByQuestionId(Long id) throws DataAccessException {
        return questionOptionDAO.findByQuestionId(id);
    }

    @Transactional(readOnly = false)
    public QuestionOption questionOption_merge(QuestionOption questionOption) {
        SortedSet<QuestionOption> updatedQuestionOptions = new TreeSet<QuestionOption>();
        Long questionId = questionOption.getQuestion().getId();
        Question question = questionDAO.findById(questionId);
        questionOption.setQuestion(question);
        Short order = question.updateSet(question.getOptions(), questionOption).getOrder();
        for (QuestionOption qo : question.getOptions()) {
            updatedQuestionOptions.add(questionOptionDAO.merge(qo));
        }
        question.setOptions(updatedQuestionOptions);
        question = questionDAO.merge(question);
        return question.getElement(question.getOptions(), order);
    }

    @Transactional(readOnly = false)
    public void questionOption_remove(QuestionOption questionOption) {
        Question question = questionDAO.findById(questionOption.getQuestion().getId());
        questionOptionDAO.remove(questionOption);
        question.removeGaps(question.getOptions());
    }

    @Transactional(readOnly = true)
    public void questionOption_removeQuestionOptionsByQuestionId(Long id) {
        questionOptionDAO.deleteByQuestionId(id);
    }

    public QuestionRowLabel questionRowLabel_findById(Long id) {
        return questionRowLabelDAO.findById(id);
    }

    public Set<QuestionRowLabel> questionRowLabel_findByQuestionId(Long id) throws DataAccessException {
        return questionRowLabelDAO.findByQuestionId(id);
    }

    @Transactional(readOnly = false)
    public QuestionRowLabel questionRowLabel_merge(QuestionRowLabel questionRowLabel) {
        return questionRowLabelDAO.merge(questionRowLabel);
    }

    @Transactional(readOnly = false)
    public void questionRowLabel_remove(QuestionRowLabel questionRowLabel) {
        Question question = questionDAO.findById(questionRowLabel.getQuestion().getId());
        questionRowLabelDAO.remove(questionRowLabel);
        question.removeGaps(question.getOptions());
    }

    public QuestionColumnLabel questionColumnLabel_findById(Long id) {
        return questionColumnLabelDAO.findById(id);
    }

    public Set<QuestionColumnLabel> questionColumnLabel_findByQuestionId(Long id) throws DataAccessException {
        return questionColumnLabelDAO.findByQuestionId(id);
    }

    @Transactional(readOnly = false)
    public QuestionColumnLabel questionColumnLabel_merge(QuestionColumnLabel questionColumnLabel) {
        return questionColumnLabelDAO.merge(questionColumnLabel);
    }

    @Transactional(readOnly = false)
    public void questionColumnLabel_remove(QuestionColumnLabel questionColumnLabel) {
        Question question = questionDAO.findById(questionColumnLabel.getQuestion().getId());
        questionColumnLabelDAO.remove(questionColumnLabel);
        question.removeGaps(question.getOptions());
    }

    public Set<Question> question_findAll() throws DataAccessException {
        return questionDAO.findAll();
    }

    public Set<Question> question_findAll(int startResult, int maxRows) throws DataAccessException {
        return questionDAO.findAll(startResult, maxRows);
    }

    public Long question_getCount() {
        return questionDAO.getCount();
    }

    public Question question_findById(Long id) {
        return questionDAO.findById(id);
    }

    public Question question_findByOrder(Long surveyDefinitionId, Short pageOrder, Short questionOrder) {
        return questionDAO.findByOrder(surveyDefinitionId, pageOrder, questionOrder);
    }

    @Transactional(readOnly = false)
    public Question question_merge(Question question) {

        Long dataSetId = null;
        if (question.getPage().getSurveyDefinition().getStatus().equals(SurveyDefinitionStatus.I)) {
            if (question.getType().getIsDataSet()) {
                dataSetId = question.getDataSetId();
                question.setType(QuestionType.SINGLE_CHOICE_DROP_DOWN);
                question.setDataSetId(null);
            }

            // Deleting options from question that do not support options
            if (!question.getSuportsOptions()) {
                questionOptionDAO.deleteByQuestionId(question.getId());
            }
            SortedSet<Question> updatedQuestions = new TreeSet<Question>();
            Long pageId = question.getPage().getId();
            SurveyDefinitionPage surveyDefinitionPage = surveyDefinitionPageDAO.findById(pageId);
            question.setPage(surveyDefinitionPage);

            question.setDataSetId(null);

            Short order = surveyDefinitionPage.updateSet(surveyDefinitionPage.getQuestions(), question)
                    .getOrder();
            for (Question q : surveyDefinitionPage.getQuestions()) {
                updatedQuestions.add(questionDAO.merge(q));
            }
            surveyDefinitionPage.setQuestions(updatedQuestions);
            surveyDefinitionPage = surveyDefinitionPageDAO.merge(surveyDefinitionPage);

            Question updatedquestion = surveyDefinitionPage.getElement(surveyDefinitionPage.getQuestions(),
                    order);

            if (dataSetId != null) {
                Short o = 1;
                for (DataSetItem dataSetItem : dataSetItemDAO.findByDataSetId(dataSetId)) {
                    questionOptionDAO.merge(new QuestionOption(updatedquestion, o, dataSetItem.getValue(),
                            dataSetItem.getText()));
                    o++;
                }
            }

            return updatedquestion;
        } else {

            Question dbQuestion = questionDAO.findById(question.getId());
            dbQuestion.setTip(question.getTip());
            dbQuestion.setQuestionText(question.getQuestionText());
            return questionDAO.merge(dbQuestion);
        }

    }

    @Transactional(readOnly = false)
    public Question question_merge(Question question, SortedSet<QuestionOption> options) {
        // Clear data set field for non Dataset questions
        if (!question.getType().getIsDataSet()) {
            question.setDataSetId(null);
        }
        // Deleting options from question that do not support options
        if (!question.getSuportsOptions()) {
            questionOptionDAO.deleteByQuestionId(question.getId());
        }

        SortedSet<Question> updatedQuestions = new TreeSet<Question>();
        Long pageId = question.getPage().getId();
        SurveyDefinitionPage surveyDefinitionPage = surveyDefinitionPageDAO.findById(pageId);
        question.setPage(surveyDefinitionPage);
        Short order = surveyDefinitionPage.updateSet(surveyDefinitionPage.getQuestions(), question).getOrder();
        for (Question q : surveyDefinitionPage.getQuestions()) {
            updatedQuestions.add(questionDAO.merge(q));
        }
        surveyDefinitionPage.setQuestions(updatedQuestions);
        surveyDefinitionPage = surveyDefinitionPageDAO.merge(surveyDefinitionPage);

        Question q = surveyDefinitionPage.getElement(surveyDefinitionPage.getQuestions(), order);

        for (QuestionOption questionOption : options) {
            questionOption.setQuestion(q);
            questionOption = questionOptionDAO.merge(questionOption);
        }
        q.setOptions(options);
        return q;

    }

    @Transactional(readOnly = false)
    public Question question_updateOptions(Question question) {
        Long questionId = question.getId();
        Question q = questionDAO.findById(questionId);
        questionOptionDAO.deleteByQuestionId(questionId);
        SortedSet<QuestionOption> options = new TreeSet<QuestionOption>();
        for (QuestionOption option : question.getOptionsList2()) {

            if (option.getValue() != null && option.getText() != null && option.getValue().trim().length() > 0
                    && option.getText().trim().length() > 0) {
                QuestionOption questionOption = new QuestionOption(q, option.getOrder(), option.getValue(),
                        option.getText());
                questionOption = questionOptionDAO.merge(questionOption);
                options.add(questionOption);
            }
        }
        q.setOptions(options);
        return questionDAO.merge(q);
    }

    @Transactional(readOnly = false)
    public Question question_updateColumnLabels(Question question) {
        Long questionId = question.getId();
        Question q = questionDAO.findById(questionId);
        questionColumnLabelDAO.deleteByQuestionId(questionId);
        SortedSet<QuestionColumnLabel> options = new TreeSet<QuestionColumnLabel>();
        for (QuestionColumnLabel columnLabel : question.getColumnLabelsList()) {

            if (columnLabel.getLabel() != null && columnLabel.getLabel().trim().length() > 0) {
                QuestionColumnLabel questionColumnLabel = new QuestionColumnLabel(q, columnLabel.getOrder(),
                        columnLabel.getLabel());
                questionColumnLabel = questionColumnLabelDAO.merge(questionColumnLabel);
                options.add(questionColumnLabel);
            }
        }
        q.setColumnLabels(options);
        return questionDAO.merge(q);
    }

    @Transactional(readOnly = false)
    public Question question_updateRowLabels(Question question) {
        Long questionId = question.getId();
        Question q = questionDAO.findById(questionId);
        questionRowLabelDAO.deleteByQuestionId(questionId);
        SortedSet<QuestionRowLabel> options = new TreeSet<QuestionRowLabel>();
        for (QuestionRowLabel rowLabel : question.getRowLabelsList()) {

            if (rowLabel.getLabel() != null && rowLabel.getLabel().trim().length() > 0) {
                QuestionRowLabel questionRowLabel = new QuestionRowLabel(q, rowLabel.getOrder(),
                        rowLabel.getLabel());
                questionRowLabel = questionRowLabelDAO.merge(questionRowLabel);
                options.add(questionRowLabel);
            }
        }
        q.setRowLabels(options);
        return questionDAO.merge(q);
    }

    @Transactional(readOnly = false)
    public Long question_remove(Long questionId) {
        Question question = questionDAO.findById(questionId);
        Long pageId = question.getPage().getId();
        log.info("deleting  questionOptions");
        questionOptionDAO.deleteByQuestionId(question.getId());
        question.setOptions(null);
        questionDAO.remove(question);
        SurveyDefinitionPage surveyDefinitionPage = surveyDefinitionPageDAO
                .findById(question.getPage().getId());
        surveyDefinitionPage.removeGaps(surveyDefinitionPage.getQuestions());
        surveyDefinitionPageDAO.merge(surveyDefinitionPage);
        return pageId;

    }

    public Set<DataSet> dataSet_findAll() throws DataAccessException {
        return dataSetDAO.findAll();
    }

    public Set<DataSet> dataSet_findAll(int startResult, int maxRows) throws DataAccessException {
        return dataSetDAO.findAll(startResult, maxRows);
    }

    public Long dataSet_getCount() {
        return dataSetDAO.getCount();
    }

    public DataSet dataSet_findById(Long id) {
        return dataSetDAO.findById(id);
    }

    /*
    public DataSet dataset_findByCode(String code) {
    	return dataSetDAO.findByCode(code);
    	}
     */
    public DataSet dataset_findByName(String name) {
        return dataSetDAO.findByName(name);
    }

    @Transactional(readOnly = false)
    public DataSet dataSet_merge(DataSet dataSet) {
        return dataSetDAO.merge(dataSet);
    }

    @Transactional(readOnly = false)
    public void dataSet_remove(Long id) {
        dataSetItemDAO.deleteByDataSetId(id);
        DataSet dataSet = dataSetDAO.findById(id);
        dataSet.setItems(null);
        dataSetDAO.remove(dataSet);
    }

    public Set<DataSetItem> datasetItem_findAll() throws DataAccessException {
        return dataSetItemDAO.findAll();
    }

    public Set<DataSetItem> datasetItem_findAll(int startResult, int maxRows) throws DataAccessException {
        return dataSetItemDAO.findAll(startResult, maxRows);
    }

    public Long datasetItem_getCount(Long id) {
        return dataSetItemDAO.getCount(id);
    }

    public DataSetItem datasetItem_findById(Long id) {
        return dataSetItemDAO.findById(id);
    }

    public Set<DataSetItem> datasetItem_findByDataSetId(Long id) throws DataAccessException {
        return dataSetItemDAO.findByDataSetId(id);
    }

    public Set<DataSetItem> datasetItem_findByDataSetId(Long id, int startResult, int maxRows)
            throws DataAccessException {
        return dataSetItemDAO.findByDataSetId(id, startResult, maxRows);
    }

    @Transactional(readOnly = false)
    public DataSetItem datasetItem_merge(DataSetItem dataSetItem) {
        return dataSetItemDAO.merge(dataSetItem);
    }

    @Transactional(readOnly = false)
    public void datasetItem_remove(DataSetItem dataSetItem) {
        dataSetItemDAO.remove(dataSetItem);
    }

    @Transactional(readOnly = false)
    public void datasetItem_deleteByDataSetId(Long datasetId) {
        dataSetItemDAO.deleteByDataSetId(datasetId);
    }

    @Transactional(readOnly = false)
    public void importDatasetItems(CSVReader csvReader, Long datasetId, Boolean ignoreFirstRow) {
        try {
            DataSet dataSet = dataSetDAO.findById(datasetId);
            dataSetItemDAO.deleteByDataSetId(datasetId);

            Integer order = 1;
            short valueFieldIndex = 0;
            short textFieldIndex = 1;
            Boolean autoGenerateValues = false;
            DataSetItem dataSetItem;

            String[] nextLine;
            while ((nextLine = csvReader.readNext()) != null) {
                // skip first row
                if (ignoreFirstRow) {
                    // Will skip the first row the continue on with loop
                    ignoreFirstRow = false;
                    continue;
                }
                if (order == 1) { // check the first Row
                    if (nextLine.length == 1) {
                        // only one column
                        autoGenerateValues = true;
                        textFieldIndex = 0;
                    } else {
                        // more than one column use the first two
                        autoGenerateValues = false;
                        if (nextLine[0].trim().length() > nextLine[1].trim().length()) {
                            // invert the indexes
                            valueFieldIndex = 1;
                            textFieldIndex = 0;
                        }
                    }
                }
                if (autoGenerateValues) {
                    dataSetItem = new DataSetItem(dataSet, order, order.toString(),
                            nextLine[textFieldIndex].trim());
                } else {
                    dataSetItem = new DataSetItem(dataSet, order, nextLine[valueFieldIndex].trim(),
                            nextLine[textFieldIndex].trim());
                }
                dataSetItemDAO.merge(dataSetItem);
                order++;
            }
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            throw new RuntimeException(e);
        }
    }

    public String exportDatasetItemsToCommaDelimited(Long datasetId) {
        try {
            DataSetItem dataSetItem;
            StringBuilder stringBuilder = new StringBuilder();
            stringBuilder.append("value,text\n");
            Set<DataSetItem> dataSetItems = dataSetItemDAO.findByDataSetId(datasetId);
            Iterator<DataSetItem> it;
            it = dataSetItems.iterator();
            while (it.hasNext()) {
                dataSetItem = it.next();
                stringBuilder.append(dataSetItem.getValue());
                stringBuilder.append(",");
                stringBuilder.append(dataSetItem.getText());
                stringBuilder.append("\n");
            }
            return stringBuilder.toString();
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            throw new RuntimeException(e);
        }
    }

    public SortedSet<Invitation> invitation_findSurveyAll(Long surveyDefinitionId) throws DataAccessException {
        return invitationDAO.findSurveyAll(surveyDefinitionId);
    }

    public SortedSet<Invitation> invitation_findSurveyAll(Long surveyDefinitionId, int startResult, int maxRows)
            throws DataAccessException {
        return invitationDAO.findSurveyAll(surveyDefinitionId, startResult, maxRows);
    }

    public Long invitation_getSurveyCount(Long surveyDefinitionId) {
        return invitationDAO.getSurveyCount(surveyDefinitionId);
    }

    public Long invitation_getSurveyOpenedCount(Long surveyDefinitionId) {
        return invitationDAO.getSurveyOpenedCount(surveyDefinitionId);
    }

    public Invitation invitation_findById(Long id) {
        return invitationDAO.findById(id);
    }

    public Invitation invitation_findByUuid(String uuid) {
        return invitationDAO.findByUuid(uuid);
    }

    public SortedSet<Invitation> invitation_searchByFirstName(String firstName) {
        return invitationDAO.searchByFirstName(firstName);
    }

    public SortedSet<Invitation> invitation_searchByLastName(String lastName) {
        return invitationDAO.searchByLastName(lastName);
    }

    public SortedSet<Invitation> invitation_searchByFirstNameAndLastName(String firstName, String lastName) {
        return invitationDAO.searchByFirstNameAndLastName(firstName, lastName);
    }

    public SortedSet<Invitation> invitation_searchByEmail(String email) {
        return invitationDAO.searchByEmail(email);
    }

    @Transactional(readOnly = false)
    public void invitation_send(Invitation invitation, String emailSubject, String emailContent) {
        try {
            // Save the invitation entry
            invitation = invitationDAO.merge(invitation);
            // Send Invitation Email
            mailService.sendEmail(invitation.getEmail(), emailSubject, emailContent);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            throw new RuntimeException(e);
        }
    }

    @Transactional(readOnly = false)
    public void invitation_updateAsRead(Long id) {
        Invitation invitation = invitationDAO.findById(id);
        invitation.updateAsRead();
        invitationDAO.merge(invitation);
    }

    public Set<RegularExpression> regularExpression_findAll() throws DataAccessException {
        return regularExpressionDAO.findAll();
    }

    public Set<RegularExpression> regularExpression_findAll(int startResult, int maxRows)
            throws DataAccessException {
        return regularExpressionDAO.findAll(startResult, maxRows);
    }

    public Long regularExpression_getCount(Long id) {
        return regularExpressionDAO.getCount(id);
    }

    public Long regularExpression_getCount() {
        return regularExpressionDAO.getCount();
    }

    public RegularExpression regularExpression_findById(Long id) {
        return regularExpressionDAO.findById(id);
    }

    public RegularExpression regularExpression_findByName(String name) {
        return regularExpressionDAO.findByName(name);
    }

    @Transactional(readOnly = false)
    public RegularExpression regularExpression_merge(RegularExpression regularExpression) {
        return regularExpressionDAO.merge(regularExpression);
    }

    @Transactional(readOnly = false)
    public void regularExpression_remove(RegularExpression regularExpression) {
        regularExpressionDAO.remove(regularExpression);
    }

    public Set<Sector> sector_findAll() throws DataAccessException {
        return sectorDAO.findAll();
    }

    public Set<Sector> sector_findAll(int startResult, int maxRows) throws DataAccessException {
        return sectorDAO.findAll(startResult, maxRows);
    }

    public Long sector_getCount() {
        return sectorDAO.getCount();
    }

    public Sector sector_findById(Long id) {
        return sectorDAO.findById(id);
    }

    public Sector sector_findByName(String name) {
        return sectorDAO.findByName(name);
    }

    @Transactional(readOnly = false)
    public Sector sector_merge(Sector sector) {
        return sectorDAO.merge(sector);
    }

    @Transactional(readOnly = false)
    public void sector_remove(Long id) {
        surveyTemplateDAO.deleteBySectorId(id);
        Sector sector = sectorDAO.findById(id);
        sector.setTemplates(null);
        sectorDAO.remove(sector);
    }

    public Set<SurveyTemplate> surveyTemplate_findAll() throws DataAccessException {
        return surveyTemplateDAO.findAll();
    }

    public Set<SurveyTemplate> surveyTemplate_findAll(int startResult, int maxRows) throws DataAccessException {
        return surveyTemplateDAO.findAll(startResult, maxRows);
    }

    public Long surveyTemplate_getCount(Long id) {
        return surveyTemplateDAO.getCount(id);
    }

    public SurveyTemplate surveyTemplate_findById(Long id) {
        return surveyTemplateDAO.findById(id);
    }

    public Set<SurveyTemplate> surveyTemplate_findBySectorId(Long id) throws DataAccessException {
        return surveyTemplateDAO.findBySectorId(id);
    }

    public Set<SurveyTemplate> surveyTemplate_findBySectorId(Long id, int startResult, int maxRows)
            throws DataAccessException {
        return surveyTemplateDAO.findBySectorId(id, startResult, maxRows);
    }

    @Transactional(readOnly = false)
    public SurveyTemplate surveyTemplate_merge(SurveyTemplate surveyTemplate) {
        return surveyTemplateDAO.merge(surveyTemplate);
    }

    @Transactional(readOnly = false)
    public void surveyTemplate_remove(SurveyTemplate surveyTemplate) {
        surveyTemplateDAO.remove(surveyTemplate);
    }

    @Transactional(readOnly = false)
    public void surveyTemplate_deleteBySectorId(Long sectorId) {
        surveyTemplateDAO.deleteBySectorId(sectorId);
    }

    public boolean surveyTemplate_ValidateNameIsUnique(SurveyTemplate surveyTemplate) {

        Boolean isValid = true;
        // get all survey definitions with the same name
        Set<SurveyTemplate> surveyTemplates = surveyTemplateDAO.findByName(surveyTemplate.getName());

        // Insert case null id
        if (surveyTemplate.getId() == null) {

            // check that there are not survey types with the same name under the current
            // department
            for (SurveyTemplate appType : surveyTemplates) {
                if (appType.getSector().getId().equals(surveyTemplate.getSector().getId())) {
                    isValid = false;
                    break;
                }
            }
        }
        // Update case id not null
        else {
            // check that there are no other survey types with the same name under the current
            // department
            for (SurveyTemplate appType : surveyTemplates) {
                if (appType.getSector().getId().equals(surveyTemplate.getSector().getId())
                        && !appType.getId().equals(surveyTemplate.getId())) {
                    isValid = false;
                    break;
                }
            }
        }
        return isValid;
    }

    @Transactional(readOnly = false)
    public Set<Day> day_findAll() throws DataAccessException {
        return dayDAO.findAll();
    }

    @Transactional(readOnly = false)
    public Day day_findById(Long id) throws DataAccessException {
        return dayDAO.findById(id);

    }

}
